package AmbientNetwork;

import java.util.*;

/**
 * Ez az osztály tartalmazza a hálózatban szereplő Node-ok listáját.
 * Ez az osztály felelős a szimuláció lefutásáért.
 * @author D-Torus-Team
 */
public class FullNetwork {

    /**
     * Kezdetben az összes peer a members-ben van. Amint elkezdenek kialakulni a hálózatok azok is ebbe kerülnek, és a külön álló peer-ek kikerülnek.
     */
    private List<Node> members;

    FullNetwork() {
    }

    /**
     * Konstruktor
     * @param m A kezdeti peerek listája.
     */
    FullNetwork(List<Node> m) {
        this.members = m;
    }

    /**
     * Visszadja az aktuális hálózati elemeket (peerek, an-ek)
     * @return members
     */
    public List<Node> getMembers() {
        return this.members;
    }

    /**
     * Végigmegy a members listán, és meghívja minden node-ra a .printMessage fv-t. Később ki fog kerülni a kódból!
     */
//    public void printMembers() {
//        ListIterator<Node> it = members.listIterator();
//        while (it.hasNext()) {
//            it.next().printMessage();
//        }
//    }

    /**
     * A megadott Node-listából véletlenszerűen választ egy node-ot
     * @param n A node lista.
     * @param random Egy random változó.
     * @return A véletlenszerűen választott node-dal.
     */
    private Node randomNode(List<Node> n, Random random) {
        Iterator<Node> it = n.iterator();
        int listLength = 0;
        while (it.hasNext()) { // Megnézzük, hogy milyen hosszú a node lista.
            listLength++;
            it.next();
        }
        it = n.iterator();
        //if(listLength==0) System.out.println(" ----------- Nincs elem a listában! -------------");
        int rand = random.nextInt(listLength + 1); /** Kérünk egy random számot 0 és a node lista hossza között.*/
        System.out.println("Random: " + rand);
        for (int i = 0; i < (rand - 1); i++) {
            if (it.hasNext()) {
                it.next(); // Ellépkedünk a megadott node-ig.
            } else {
                System.out.println("SZAAAAAAAAAAAAAAAAAAAAAAAAR");
            }
        }
        return it.next();

    }
/**
 * Ez a függvény felelős a teljes szimulációért. Ez hívja meg a ConnectionLogic osztály megfelelő függvényét.
 * A  policy-knek megfelelő események után végrehatja a megfelelő eseményeket: pl.: hozzáadja a members listához az újonnan kialakult hálózatot, és törli a megfelelő peereket.
 * Egyelőre egyszerűsített verzióban működik, nem várja meg, hogy kialakuljon egy végleges állapot, csak addig szimulál, amíg vannak peer-ek a members listában.
 */
    public void simulate() {
        ListIterator<Node> it = members.listIterator();
        ConnectionLogic.init();                      // Ez a Node ID-khoz kell
        Random random = new Random();                // Ez a random node választáshoz kell.
        int i = 0;                                   // Ebben a változóban tárolódik, hogy aktuálisan épp hány peer van még a members listában.
        boolean end = false;                         // Amíg ez false addig tesztelünk. Akkor lesz true, ha nincs több peer azaz i==0
        while (!end) {
            while (it.hasNext()) {
                if (it.next().getIsPeer()) {
                    i++;

                }
            }

            if (i != 0) {                                                           //Ha még van peer:
                Node probe = randomNode(members, random);                           //Random választunk egy node-ot a members listából
                Node probeNeighbours = randomNode(probe.getNeighbours(), random);   //Randomra választunk az előbb kiválasztott peer szomszédai közül egy node-ot
                Node tmp = ConnectionLogic.merge(probe, probeNeighbours);           //Ezeket elküldjük, hogy ha tudnak akkor kezdjenek egymással valamit.
                if (tmp.getID() != 0) {                                             // Akkor lenne 0 az ID-ha nem tudnának gateway-ezni sem, ekkor új random nodeokat kell választani
                    members.add(tmp);                                               //Különben hozzáadjuk az új AN-t a members listához
                    if (probe.getIsPeer()) {                                        //Ha a két vizsgált node peer volt, akkor töröljük a members listáról őket
                        members.remove(probe);

                    }
                    if (probeNeighbours.getIsPeer()) {
                        members.remove(probeNeighbours);

                    }
                }
                //printMembers();
                i = 0;
            } else {
                end = true;
            }
            it = members.listIterator(); // Ez azért kell, mert közben megváltozott a members lista, és nehogy elromoljon az iterátor, meg hogy visszaáljon az elejére

        }

    }
    // return 1;
    }


